/*
 * Yguan - Yui Gwt Unified ANimation
 *
 * Copyright (c) 2009, Yves Cuillerdier
 * All rights reserved.
 * 
 * This software is licensed under the new BSD License:
 * 
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, 
 * this list of conditions and the following disclaimer.
 * 
 * Redistributions in binary form must reproduce the above copyright notice, 
 * this list of conditions and the following disclaimer in the documentation 
 * and/or other materials provided with the distribution.
 * 
 * Neither the name of the author nor the names of its contributors may 
 * be used to endorse or promote products derived from this software without 
 * specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 * POSSIBILITY OF SUCH DAMAGE.
 * 
 * @version 0.1.0
 */
package gyraf.core.client.animation;

import gyraf.wrapper.client.event.EventHandlerUtil;
import gyraf.wrapper.client.event.EventListenerUtil;
import yocef.client.Event;
import yocef.client.EventBind;
import yocef.client.EventGlue;

import com.google.gwt.core.client.JavaScriptObject;

/**
 * Glue for the animation events.
 */
public final class AnimatorGlue extends EventGlue {

	/**
	 * Build and register a Glue for the YUI Animation's Events.
	 */
	public AnimatorGlue() {
		super(Animation.class);
	}

	/**
	 * Glue the native Animation event on the element.
	 * 
	 * @param binding
	 *            the Event-Element binding to be wired with the Amination's
	 *            events.
	 */
	@Override
	public boolean accept(final EventBind binding) {
		// This is only for the Animation class!
		final Object element = binding.getSource();
		if (!(element instanceof Animation)) {
			return false;
		}
		final Animation anim = (Animation) element;
		// The event
		final Event event = binding.getEvent();
		// build the handler
		JavaScriptObject animJs;
		JavaScriptObject handler;
		String yuiName;
		if (event == AnimationEvent.ElementAnimationStart.event()) {
			// for "start" we bind the first animation
			animJs = anim.getFirstJsObject();
			handler = EventHandlerUtil.getJsNoParamHandler(binding);
			yuiName = "onStart";
		} else if (event == AnimationEvent.DuringElementAnimation.event()) {
			// for "during" we bind the last animation
			animJs = anim.getLastJsObject();
			handler = EventHandlerUtil.getJsNoParamHandler(binding);
			yuiName = "onTween";
		} else if (event == AnimationEvent.ElementAnimationStop.event()) {
			// for "stop" we bind the last animation
			animJs = anim.getLastJsObject();
			handler = getOnCompleteHandler(binding);
			yuiName = "onComplete";
		} else {
			return false;
		}
		// Subscribe
		EventListenerUtil.elementEventSubscribe(animJs, yuiName, handler);
		// Save the data needed by unsubscribe
		binding.addData("animJs", animJs);
		binding.addData("handler", handler);
		binding.addData("event", yuiName);
		return true;
	}

	/**
	 * Unglued the native Animation event from the element.
	 * 
	 * @param binding
	 *            the Event-Element binding to be unwired from the Amination's
	 *            events.
	 */
	@Override
	public boolean release(final EventBind binding) {
		final Object element = binding.getSource();
		if (!(element instanceof Animation)) {
			return false;
		}
		final Event event = binding.getEvent();
		if (event == AnimationEvent.ElementAnimationStart.event()
				|| event == AnimationEvent.DuringElementAnimation.event()
				|| event == AnimationEvent.ElementAnimationStop.event()) {
			EventListenerUtil.elementEventUnsubscribe(
					(JavaScriptObject) binding.getData("animJs"),
					(String) binding.getData("event"),
					(JavaScriptObject) binding.getData("handler"));
		} else {
			return false;
		}
		return true;
	}

	/**
	 * OnComplete Handler
	 * <p>
	 * Params are in array args (2nd argument)
	 * 
	 * @see ElementAnimationStopParams
	 */
	private static native JavaScriptObject getOnCompleteHandler(
			EventBind binding) /*-{
		var handler = function(sType, aArgs) {
			// Get params
			var arg = aArgs[0];
			var param = @yocef.client.EventParams::new()();
			param.@yocef.client.EventParams::put(Ljava/lang/String;I)("frames",arg.frames);
			param.@yocef.client.EventParams::put(Ljava/lang/String;D)("fps",arg.fps);
			param.@yocef.client.EventParams::put(Ljava/lang/String;D)("duration",arg.duration);
			// Call action
			var event = binding.@yocef.client.EventBind::getEvent()(); // un Lyocef/client/Event;
			var element = binding.@yocef.client.EventBind::getSource()(); // un Ljava/lang/Object;
			var context = binding.@yocef.client.EventBind::getContext()(); // un Lyocef/client/EventContext;
			var action = binding.@yocef.client.EventBind::getAction()(); 
	        return action.@yocef.client.EventAction::handle(Lyocef/client/Event;Ljava/lang/Object;Lyocef/client/EventContext;Lyocef/client/EventParams;)(event, element, context, param);
		};
		return handler;		
	}-*/;
}
